package com.zwps.common.controller.config;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.springdoc.core.AbstractRequestService;
import org.springdoc.core.GenericResponseService;
import org.springdoc.core.OpenAPIService;
import org.springdoc.core.OperationService;
import org.springdoc.core.PropertyResolverUtils;
import org.springdoc.core.ReturnTypeParser;
import org.springdoc.core.SpringDocConfigProperties;
import org.springdoc.core.SpringDocProviders;
import org.springdoc.core.customizers.OperationCustomizer;
import org.springdoc.core.customizers.RouterOperationCustomizer;
import org.springdoc.core.customizers.SpringDocCustomizers;
import org.springdoc.core.fn.RouterOperation;
import org.springdoc.webmvc.api.OpenApiWebMvcResource;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import com.zwps.common.controller.config.properties.ApplicationConfig;
import com.zwps.common.controller.constant.HttpHeaderConstant;
import com.zwps.common.controller.constant.ShiroConstant;
import com.zwps.common.controller.swagger.SwaggerResponseWrapper;

import cn.hutool.core.util.StrUtil;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.parameters.HeaderParameter;
import io.swagger.v3.oas.models.parameters.Parameter;

@Configuration
public class SwaggerProcessConfig {

    @Autowired
    private ApplicationConfig applicationConfig;

    @Autowired
    private ShiroFilterFactoryBean shiroFilterFactoryBean;

    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    @Value("${server.servlet.context-path:/}")
    private String serverContextPath;

    public final RouterOperationCustomizer addApiPrefix = (routerOperation,
            handlerMethod) -> addApiPrefix(routerOperation);

//    private  Schema<?> defaultResponseMessageSchema;
//
//    public SwaggerTokenHeaderProcessConfig() {
//        defaultResponseMessageSchema = AnnotationsUtils.resolveSchemaFromType(DefaultResponseMessage.class, null, null);
//    }

    /**
     * 处理加上server.servlet.context-path前缀
     * 处理当文档访问地址为（http://192.168.17.222:8100/system/v3/api-docs）
     * 如果地址为（http://192.168.17.222:8100/system/v3/api-docs/yskj-system）则不会进入该处理代码，yskj-system服务名，system是接口前缀
     * 
     * @Title: openApiResource
     * @Description:
     * @param openAPIBuilderObjectFactory
     * @param requestBuilder
     * @param responseBuilder
     * @param operationParser
     * @param springDocConfigProperties
     * @param springDocProviders
     * @param springDocCustomizers
     * @return OpenApiWebMvcResource
     * @author lyh
     * @date 2023年8月1日 下午3:36:27
     */
    @Bean
    public OpenApiWebMvcResource openApiResource22(ObjectFactory<OpenAPIService> openAPIBuilderObjectFactory,
            AbstractRequestService requestBuilder, GenericResponseService responseBuilder,
            OperationService operationParser, SpringDocConfigProperties springDocConfigProperties,
            SpringDocProviders springDocProviders, SpringDocCustomizers springDocCustomizers) {
        return new OpenApiWebMvcResource(openAPIBuilderObjectFactory, requestBuilder, responseBuilder, operationParser,
                springDocConfigProperties, springDocProviders, springDocCustomizers) {
            @Override
            protected void calculatePath(HandlerMethod handlerMethod, RouterOperation routerOperation, Locale locale,
                    OpenAPI openAPI) {
                addApiPrefix(routerOperation);
                super.calculatePath(handlerMethod, routerOperation, locale, openAPI);
            }
        };
    }

    private RouterOperation addApiPrefix(RouterOperation routerOperation) {
        if (!(StrUtil.isEmpty(serverContextPath) || "/".equals(serverContextPath))) {
            routerOperation.setPath(serverContextPath + routerOperation.getPath());
        }
        return routerOperation;
    }

    @Bean
    public GenericResponseService responseBuilder(OperationService operationService,
            List<ReturnTypeParser> returnTypeParsers, SpringDocConfigProperties springDocConfigProperties,
            PropertyResolverUtils propertyResolverUtils) {
        return new SwaggerResponseWrapper(operationService, returnTypeParsers, springDocConfigProperties,
                propertyResolverUtils);
    }

    @Bean
    public OpenAPI customOpenAPI() {
        OpenAPI openAPI = new OpenAPI().info(
                new Info().title(applicationConfig.getName() + " " + applicationConfig.getActive()).extensions(null)
                        .version(applicationConfig.getVersion()).description(applicationConfig.getDescription()));
        // 这个代码无效，没有找到定位到原因
//        Components components = openAPI.getComponents();
//        if (components == null) {
//            openAPI.setComponents( components = new Components());
//        }
//        components.addSchemas(DefaultResponseMessage.class.getName(), defaultResponseMessageSchema);
        return openAPI;
    }

    /**
     * 全局添加请求头
     * 
     * @Title: addAuthorizationHeader
     * @Description: 给需要登录校验的接口加上token请求头
     * @return OperationCustomizer
     * @author lyh
     * @date 2023年5月19日 下午9:57:59
     */
    public OperationCustomizer addAuthorizationHeader() {
        return (operation, handlerMethod) -> {

            Map<String, String> filters = shiroFilterFactoryBean.getFilterChainDefinitionMap();
            AntPathMatcher matcher = new AntPathMatcher();
            boolean needAuthorization = true;
            if (filters != null && !filters.isEmpty()) {
                RequestMappingInfo requestMappingInfo = getRequestMappingInfo(handlerMethod);
                if (requestMappingInfo != null) {

                    for (Entry<String, String> entry : filters.entrySet()) {
                        String filterName = entry.getValue();
                        // 过滤需要登录的url
                        if (!ShiroConstant.FILTER_NAME_ANON.equalsIgnoreCase(filterName)) {
                            continue;
                        }
                        String path = requestMappingInfo.getPatternsCondition().getPatterns().iterator().next();
                        // 当前url不需要登录
                        if (matcher.match(entry.getKey(), path)) {
                            needAuthorization = false;
                            break;
                        }
                    }
                }
            }
//            ApiResponses apiResponses = operation.getResponses();

//            addApiResponse(apiResponses, CommonExceptionStatus.USER_ACTION_SUCCESS);
//            addApiResponse(apiResponses, CommonExceptionStatus.USER_ACTION_FAILURE);
//            addApiResponse(apiResponses, CommonExceptionStatus.PARAMETER_NOT_MEET_REQUIRE);
//
//            addApiResponse(apiResponses, CommonExceptionStatus.AUTHENTICATION_FAILURE);
//            addApiResponse(apiResponses, CommonExceptionStatus.PARAMETER_ERROR);
//            addApiResponse(apiResponses, CommonExceptionStatus.SERVE_ERROR);
//            addApiResponse(apiResponses, CommonExceptionStatus.UNSUPPORTED_REQUEST_METHOD);

            if (needAuthorization) {
                List<Parameter> globalParameters = operation.getParameters();
                if (globalParameters == null) {
                    globalParameters = new ArrayList<>();
                }
                HeaderParameter header = new HeaderParameter();
                header.setName(HttpHeaderConstant.HEADER_TOKEAN);
                header.required(true);
                header.setDescription("Token值，用于登录验证");
                globalParameters.add(header);
                operation.setParameters(globalParameters);
            }
            return operation;
        };
    }

//    private ApiResponses addApiResponse(ApiResponses apiResponses, CommonExceptionStatus status) {
//        Content content = new Content().addMediaType(org.springframework.http.MediaType.APPLICATION_JSON_VALUE,
//                new MediaType().schema(defaultResponseMessageSchema));
//        apiResponses.addApiResponse(status.getCode() + "",
//                new ApiResponse().description(status.getDescribe()).content(content));
//        return apiResponses;
//    }

    private RequestMappingInfo getRequestMappingInfo(HandlerMethod handlerMethod) {
        for (Entry<RequestMappingInfo, HandlerMethod> entry : requestMappingHandlerMapping.getHandlerMethods()
                .entrySet()) {
            if (entry.getValue() == handlerMethod) {
                return entry.getKey();
            }
        }
        return null;
    }
}
